package breakthrough.AlphaBetaPlayer.Evaluation;

import game.GameState;
import breakthrough.BreakthroughState;

/**
 * Evaluates an individual pawn on the board using the weights given
 * in the Feature enum
 * 
 * @author oberliat
 */
public class EvaluatedPiece {
	
	private double value;
	private BreakthroughState board;
	private int row, col;
	private char team;
	private boolean piecesTurn;
	
	public EvaluatedPiece(BreakthroughState board, int row, int col, char team) {
		this.board = board;
		this.row = row;
		this.col = col;
		this.team = team;
		GameState.Who us = team == BreakthroughState.homeSym ? GameState.Who.HOME : GameState.Who.AWAY;
		this.piecesTurn = this.board.who == us;
		this.value = this.evaluate();
	}
	
	private double evaluate() {
		if (this.pieceWins()) {
			return Feature.WINNING_POSITION.getWeight();
		}
		
		double value = Feature.PIECE_VALUE.getWeight();
		
		if (this.pieceAlmostWins()) {
			value += Feature.PIECE_ALMOST_WIN.getWeight();
		}
		
		value += Feature.PIECE_DISTANCE_FROM_WIN.getWeight() * this.pieceDistanceFromWin();
		
		value += Feature.HORIZONTAL_CONNECTION.getWeight() * this.horizontalConnection();
		
		value += Feature.VERTICAL_CONNECTION.getWeight() * this.verticalConnection();
		
		value += Feature.PIECE_MOBILITY.getWeight() * this.pieceMobility();
		
		if (this.pieceInBackRow()) {
			value += Feature.PIECE_IN_BACK_ROW.getWeight();
		}
		
		value += Feature.PIECE_PROTECTION.getWeight() * this.pieceProtection();
		
		value -= Feature.PIECE_DANGER.getWeight() * this.pieceDanger();
		
		return value;
	}
	
	public double getValue() {
		return this.value;
	}
	
	private boolean pieceWins() {
		if (this.team == BreakthroughState.homeSym) {
			if (this.row == BreakthroughState.N-1) {
				return true;
			}
		} else {
			if (this.row == 0) {
				return true;
			}
		}
		
		return false;
	}
	
	private boolean pieceAlmostWins() {
		int direction = this.team == BreakthroughState.homeSym ? 2 : -2;
		boolean valid = (direction == 2 && this.row == BreakthroughState.N -3) || (direction == -2 && this.row == 2);
		
		if (valid) {
			if (this.col >= 2 && this.col <= BreakthroughState.N - 3) {
				if (this.board.board[this.row+direction][this.col-2] == BreakthroughState.emptySym && this.board.board[this.row+direction][this.col] == BreakthroughState.emptySym) {
					return true;
				}
				if (this.board.board[this.row+direction][this.col-1] == BreakthroughState.emptySym && this.board.board[this.row+direction][this.col+1] == BreakthroughState.emptySym) {
					return true;
				}
				if (this.board.board[this.row+direction][this.col] == BreakthroughState.emptySym && this.board.board[this.row+direction][this.col+2] == BreakthroughState.emptySym) {
					return true;
				}
			} else if (this.col == 1) {
				if (this.board.board[this.row+direction][this.col-1] == BreakthroughState.emptySym && this.board.board[this.row+direction][this.col+1] == BreakthroughState.emptySym) {
					return true;
				}
				if (this.board.board[this.row+direction][this.col] == BreakthroughState.emptySym) {
					return true;
				}
			} else if (this.col == 0 ) {
				if (this.board.board[this.row+direction][this.col] == BreakthroughState.emptySym && this.board.board[this.row+direction][this.col+2] == BreakthroughState.emptySym) {
					return true;
				}
				if (this.board.board[this.row+direction][this.col+1] == BreakthroughState.emptySym) {
					return true;
				}
			} else if (this.col == BreakthroughState.N - 2) {
				if (this.board.board[this.row+direction][this.col] == BreakthroughState.emptySym) {
					return true;
				}
				if (this.board.board[this.row+direction][this.col-1] == BreakthroughState.emptySym && this.board.board[this.row+direction][this.col+1] == BreakthroughState.emptySym) {
					return true;
				}
			} else if (this.col == BreakthroughState.N - 1) {
				if (this.board.board[this.row+direction][this.col-2] == BreakthroughState.emptySym && this.board.board[this.row+direction][this.col] == BreakthroughState.emptySym) {
					return true;
				}
				if (this.board.board[row+direction][col-1] == BreakthroughState.emptySym) {
					return true;
				}
			}
		}
		
		return false;
	}
	
	private int pieceDistanceFromWin() {
		if (this.team == BreakthroughState.awaySym) {
			return BreakthroughState.N - 1 - this.row;
		}
		else {
			return this.row;
		}
	}
	
	private int horizontalConnection() {
		int numConnections = 0;			
		
		if (this.col > 0) {
			if (this.board.board[this.row][this.col-1] == this.team) {
				numConnections++;
			}
		}
		if (this.col < BreakthroughState.N-1) {
			if (this.board.board[this.row][this.col+1] == this.team) {
				numConnections++;
			}
		}
		
		return numConnections;
	}
	
	private int verticalConnection() {
		int numConnections = 0;
		
		if (this.row > 0) {
			if (this.board.board[this.row-1][this.col] == this.team) {
				numConnections++;
			}
		}
		if (this.row < BreakthroughState.N-1) {
			if (this.board.board[this.row+1][this.col] == this.team) {
				numConnections++;
			}
		}
		
		return numConnections;
	}
	
	private int pieceMobility() {
		int mobility = 0;
		int direction = this.team == BreakthroughState.homeSym ? 1 : -1;
		boolean valid = direction == 1 ? this.row < BreakthroughState.N-1 : this.row > 0;
		
		if (valid) {
			if (this.col > 0 && this.board.board[this.row+direction][this.col-1] == BreakthroughState.emptySym) {
				mobility++;
			}
			if (this.board.board[this.row+direction][col] == BreakthroughState.emptySym) {
				mobility++;
			}
			if (this.col < BreakthroughState.N-1 && this.board.board[this.row+direction][col+1] == BreakthroughState.emptySym) {
				mobility++;
			}
		}
		
		return mobility;
	}
	
	private boolean pieceInBackRow() {
		if (this.team == BreakthroughState.homeSym) {
			if (this.row == 0) {
				return true;
			}
		} else {
			if (this.row == BreakthroughState.N-1) {
				return true;
			}
		}
		
		return false;
	}
	
	private int pieceProtection() {
		int protection = 0;
		int direction = this.team == BreakthroughState.homeSym ? -1 : 1;
		boolean valid = direction == -1 ? this.row > 0 : this.row < BreakthroughState.N-1;
		
		if (valid) {
			if (this.col > 0 && this.board.board[this.row+direction][this.col-1] == this.team) {
				protection++;
			}
			if (this.col < BreakthroughState.N-1 && this.board.board[this.row+direction][col+1] == this.team) {
				protection++;
			}
		}
		
		return protection;
	}
	
	private int pieceDanger() {
		int danger = 0;
		int direction = this.team == BreakthroughState.homeSym ? 1 : -1;
		boolean valid = direction == 1 ? this.row < BreakthroughState.N-1 : this.row > 0;
		char opponent = this.team == BreakthroughState.homeSym ? BreakthroughState.awaySym : BreakthroughState.homeSym;
		
		if (valid && !this.piecesTurn) {
			if (this.col > 0 && this.board.board[this.row+direction][this.col-1] == opponent) {
				danger++;
			}
			if (this.col < BreakthroughState.N-1 && this.board.board[this.row+direction][col+1] == opponent) {
				danger++;
			}
		}
		
		return danger;
	}
};